import sys
import os
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..'))

import logging
from datetime import datetime
from shared.utils.MySQLUtil import MySQLUtil
from fastmcp import FastMCP
from fastmcp.exceptions import ToolError
from fastmcp.tools.tool import ToolAnnotations
from typing import Annotated, Dict, Any
from pydantic import Field
import json
from starlette.requests import Request
from starlette.responses import JSONResponse
import sys
from pathlib import Path
# 添加 mcp_generator 路径
mcp_generator_path = Path(__file__).parent.parent.parent / "services" / "mcp-generator"
sys.path.append(str(mcp_generator_path))
from mcp_generator.function_manager import FunctionManager

# Initialize FastMCP server with explicit configuration
# - name: Human-readable server identifier
# - mask_error_details: Security setting to control error message exposure
mcp = FastMCP(
    name="xjcmcpServer",
    mask_error_details=True,
    host="0.0.0.0", port=8000  # Hide internal error details from clients
)

db = MySQLUtil()

logger = logging.getLogger("xjcmcp")
logging.basicConfig(level=logging.INFO)

# Initialize function manager
function_registry_path = os.path.join(os.path.dirname(__file__), "function_registry.json")
function_manager = FunctionManager(function_registry_path)

# Health check endpoint using FastMCP custom route
@mcp.custom_route("/health", methods=["GET"])
async def health_check(request: Request) -> JSONResponse:
    """Health check endpoint for monitoring server status"""
    try:
        # Test database connection
        db.test_connection()
        return JSONResponse({"status": "healthy", "timestamp": datetime.now().isoformat()})
    except Exception as e:
        logger.error(f"Health check failed: {e}")
        return JSONResponse({"status": "unhealthy", "error": str(e)}, status_code=500)

# Unified MCP tool that can call any registered function
@mcp.tool(
    name="call_indicator_function",
    description="统一的指标数据获取工具。可以调用任何已注册的指标计算函数。通过function_name参数指定要调用的函数，通过parameters字典传递函数所需的参数。",
    annotations=ToolAnnotations(
        title="指标数据获取工具",
        readOnlyHint=True,
        idempotentHint=True
    )
)
def call_indicator_function(
    function_name: Annotated[str, Field(description="要调用的函数名称（指标名称）")],
    parameters: Annotated[Dict[str, Any], Field(description="函数参数字典，包含所有需要传递给函数的参数")] = None
) -> dict:
    """
    统一的指标数据获取工具
    
    通过此工具可以调用任何已注册的指标计算函数。
    
    Args:
        function_name: 要调用的函数名称（通常是指标名称）
        parameters: 包含函数所需参数的字典
        
    Returns:
        dict: 函数执行结果
        
    Raises:
        ToolError: 当函数不存在或执行失败时
    """
    try:
        logger.info(f"调用指标函数: {function_name}, 参数: {parameters}")
        
        # 检查函数是否存在
        function_info = function_manager.get_function_info(function_name)
        if not function_info:
            available_functions = list(function_manager.functions.keys())
            raise ToolError(f"函数 '{function_name}' 不存在。可用函数: {available_functions}")
        
        # 准备参数
        if parameters is None:
            parameters = {}
        
        # 添加数据库连接到参数中
        parameters['db'] = db
        
        # 调用函数
        result = function_manager.call_function(function_name, **parameters)
        
        logger.info(f"函数 {function_name} 执行成功")
        return result
        
    except ValueError as e:
        logger.error(f"函数调用错误: {str(e)}")
        raise ToolError(str(e))
    except Exception as e:
        logger.error(f"函数 {function_name} 执行异常: {str(e)}", exc_info=True)
        raise ToolError(f"函数 '{function_name}' 执行失败: {str(e)}")

# Function list endpoint for RAG knowledge base
@mcp.custom_route("/function_list", methods=["GET"])
async def get_function_list(request: Request) -> JSONResponse:
    """Get function list for RAG knowledge base"""
    try:
        function_list = function_manager.get_function_list()
        return JSONResponse({
            "status": "success",
            "data": function_list,
            "count": len(function_list),
            "timestamp": datetime.now().isoformat()
        })
    except Exception as e:
        logger.error(f"Failed to get function list: {e}")
        return JSONResponse({"status": "error", "error": str(e)}, status_code=500)

# Function list text endpoint for RAG knowledge base
@mcp.custom_route("/function_list_text", methods=["GET"])
async def get_function_list_text(request: Request) -> JSONResponse:
    """Get function list as formatted text for RAG knowledge base"""
    try:
        function_list_text = function_manager.get_function_list_text()
        return JSONResponse({
            "status": "success",
            "data": function_list_text,
            "timestamp": datetime.now().isoformat()
        })
    except Exception as e:
        logger.error(f"Failed to get function list text: {e}")
        return JSONResponse({"status": "error", "error": str(e)}, status_code=500)

# Force reload functions endpoint (for compatibility with MCP Generator notifications)
@mcp.custom_route("/force-reload-functions", methods=["POST"])
async def force_reload_functions(request: Request) -> JSONResponse:
    """Force reload functions from registry (for MCP Generator notifications)"""
    try:
        # Reload the function registry
        function_manager.functions = function_manager._load_registry()
        function_count = len(function_manager.functions)
        logger.info(f"✅ 已重新加载 {function_count} 个函数")
        return JSONResponse({
            "message": f"已重新加载 {function_count} 个函数",
            "count": function_count,
            "timestamp": datetime.now().isoformat()
        })
    except Exception as e:
        logger.error(f"❌ 重新加载函数失败: {e}")
        return JSONResponse({"message": f"重新加载函数失败: {str(e)}"}, status_code=500)

# Server execution block
if __name__ == "__main__":
    """
    Server entry point
    
    Runs the MCP server with Server-Sent Events (SSE) transport protocol
    - Automatic tool registration handling
    - Built-in validation and error handling
    - Context-aware execution environment
    """
    try:
        # Start the MCP server with specified transport
        mcp.run(transport="sse")
    except KeyboardInterrupt:
        # Graceful shutdown on Ctrl+C
        logger.info("Shutting down MCP server...")